package com.xiao.framework.ds.autoconfigure;

import java.lang.reflect.Field;
import java.lang.reflect.Proxy;
import lombok.extern.slf4j.Slf4j;
import org.aopalliance.intercept.MethodInvocation;

/**
 * @author <a href="mailto:xiaoquanidea@163.com">hutiquan</a>
 * @since 2019-08-25 1:13
 */
@Slf4j
public class MultiDataSourceClassResolver {

    private boolean mpEnabled = false;

    private Field mapperInterfaceField; //mapperInterfaceField中存放的是mybatis mapper接口的Class对象

    /**
     * {@link org.apache.ibatis.binding.MapperProxy}
     */
    public MultiDataSourceClassResolver() {
        Class<?> proxyClass = null;
        try {
            proxyClass = Class.forName("com.baomidou.mybatisplus.core.override.MybatisMapperProxy");
        } catch (ClassNotFoundException e1) {
            try {
                proxyClass = Class.forName("com.baomidou.mybatisplus.core.override.PageMapperProxy");
            } catch (ClassNotFoundException e2) {
                try {
                    proxyClass = Class.forName("org.apache.ibatis.binding.MapperProxy");
                } catch (ClassNotFoundException e3) {
                }
            }
        }
        if (proxyClass != null) {
            try {
                mapperInterfaceField = proxyClass.getDeclaredField("mapperInterface");
                mapperInterfaceField.setAccessible(true);
                mpEnabled = true;
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            }
        }
    }

    public Class<?> targetClass(MethodInvocation invocation) throws IllegalAccessException {
        //maEnabled 只有获取到mapperInterface属性字段的时候,才为true
        if (mpEnabled) {
            /**
             * 获取原对象 如果该对象是mybatisMapper jdk动态代理对象,获取该对象的 mapperInterface字段(保存了Mapper的Class对象),
             * Proxy.getInvocationHandler(target) 获取的是MapperProxy代理对象
             * 所以下方(Class<?>) mapperInterfaceField.get(Proxy.getInvocationHandler(target)) 强转为class
             */
            Object target = invocation.getThis(); //代理的目标对象(原对象)
            Class<?> targetClass = target.getClass();
            return Proxy.isProxyClass(targetClass) ? (Class<?>) mapperInterfaceField.get(Proxy.getInvocationHandler(target)) : targetClass;
        }
        return invocation.getMethod().getDeclaringClass();
    }
}
